#ifndef SERVER_HANDLE_H
#define SERVER_HANDLE_H

#include <wx/event.h>
#include <string>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <shared_mutex>
#include <map>
#include <oatpp-websocket/WebSocket.hpp>
#include "ReceiveDeviceData.h"
#include "../../../src/PixelFormat.h"

class ServerConnEvent: public wxEvent
{
public:
    ServerConnEvent(wxEventType eventType, int winid,const long deviceID, const std::string& deviceName,const std::string& ip="")
        : wxEvent(winid, eventType),DeviceName(deviceName),deviceUUID(deviceID),ipaddress(ip)
    {}
    std::string GetIpAddress() {return ipaddress;}
    std::string GetDeviceName() {return DeviceName;}
    long GetDeviceUUID(){return deviceUUID;}
    virtual wxEvent *Clone() const { return new ServerConnEvent(*this); }
private:
    std::string DeviceName;
    long deviceUUID;
    std::string ipaddress;
};

class NewImageData: public wxEvent
{
public:
    NewImageData(wxEventType eventType,int winID,const long deviceID,unsigned char* data,wxSize& size,pixelFormat _imgFormat)
        : wxEvent(winID,eventType),DeviceID(deviceID),imageData(data),imageSize(size),imgFormat(_imgFormat)
    {}

    long GetDeviceID(){return DeviceID;}
    wxSize GetSize(){return imageSize;}
    unsigned char* GetImage(){return imageData;}
    pixelFormat GetFormat() {return imgFormat;}

    virtual wxEvent* Clone() const {return new NewImageData(*this);}
private:
    long DeviceID;
    unsigned char* imageData;
    wxSize imageSize;
    pixelFormat imgFormat;
};

class DeviceMessageEvent : public wxEvent
{
public:
    DeviceMessageEvent(wxEventType eventType,int winID,const std::string& msg,const long DeviceID)
        : wxEvent(winID,eventType),message(msg),deviceID(DeviceID)
    {}
    std::string GetMessage() {return message;}
    long GetDeviceId() {return deviceID;}
    virtual wxEvent* Clone() const {return new DeviceMessageEvent(*this);}
private:
    std::string message;
    long deviceID;
};

wxDECLARE_EVENT(EVT_SERVER_CONN_NEW,ServerConnEvent);
wxDECLARE_EVENT(EVT_SERVER_CONN_CLOSE,ServerConnEvent);  //关闭设备是没有设备名，只有UUID
wxDECLARE_EVENT(EVT_SERVER_NEW_IMAGE,NewImageData);
wxDECLARE_EVENT(EVT_DEVICE_MESSAGE,DeviceMessageEvent);

struct CameraParament
{
    int32_t ImageHeight;
    int32_t ImageWidth;
    int32_t ImageOffsetX;
    int32_t ImageOffsetY;
    int32_t ExposeTime;
    int32_t FrameRate;
    int32_t TriggerMode;
};

class ServerHandle;
//用于标记每个线程，由ServerHandle同一管理

enum class FileTransfer
{
    nothing,
    ready,
    transfer,
    end
};

class ConnectHook
{
public:
    ConnectHook(wxEvtHandler* evtHandler,wxWindowID id,long DeviceID,const oatpp::websocket::WebSocket* socketAddress);
    void GetNewImage(unsigned char* data,int32_t width,int32_t height,pixelFormat imgFormat);
    void GetNewReturn(int32_t value);
    
    void SetDeviceName(std::string& data);  //调用这个函数后，设备显示到UI上
    void StartCollegeImage();
    void StopCollegeImage();
    void SendDeviceInfo();
    int32_t GetDeviceInfo();
    void InitDevice();
    void StartShot();
    void StopShot();
    void StartCollege();
    void StopCollege();
    void SendCameraParament();  //发送获取设备参数指令
    CameraParament GetCameraParament();
    void GetCameraParaReturn(char* data);
    void EnableTrigger();
    void DisableTrigger();
    void SetExposeTime(const int32_t value);
    void SetImageHeight(const int32_t value);
    void SetImageWidth(const int32_t value);
    void SetImageOffsetX(const int32_t value);
    void SetImageOffsetY(const int32_t value);
    void SetFrameRate(const int32_t value);
    void ReceiveMessage(const std::string value);
    void HandleFileTransfer(const char* data,const size_t size);
    bool FileTransferFunc(wxWindow* win,const std::string& savePath);
    void SetGetDataReady(bool value);
private:
    //文件传输
    std::mutex getFileTransferMutex;
    std::condition_variable returnFileTransferCond;
    void SendFileTranslateCommand(const int32_t& value);
    void GetFileTranslateCommand();  //仅仅用于等待数据就绪
    void ReceiveFileData();
    int64_t frameCount=0;
    bool deviceTransferReady=false;
    char dataBuff[512];
    bool translateStop=false;
    int64_t frameIndex=0;
    std::atomic<bool> fileDataReady=false;

    void SendControlCommand(int32_t value);
    void SendControlCommandAndParameter(int32_t value,const void* para,size_t psize);
    int32_t GetControlReturn(int32_t command);
    std::mutex sendDataMutex;
    std::mutex getReturnMutex;
    std::condition_variable returnDataCond;
    std::mutex getCameraParaMutex;
    std::condition_variable returnCameraParaCond;
    std::atomic<bool> GetDataReady=false;
    std::string lastSendData;

    int32_t returnValue;
    CameraParament returnCameraPara;
    friend class ServerHandle;
    wxEvtHandler* _evtHandler;
    wxWindowID winID;
    std::string deviceName;
    long deviceID;
    std::ofstream oFile;
    const oatpp::websocket::WebSocket* socketMemAddress;  //用于比较是否是同一个socket
    FileTransfer transferStatus=FileTransfer::nothing;
    std::unique_ptr<ReveiceDeviceData> receiveMsg;
};

typedef std::map<int,ConnectHook>::iterator ConnectHookPtr;

class ServerHandle
{
public:
    ServerHandle(wxEvtHandler* evtHandler,wxWindowID id);
    //int SetNewDevice(std::string deviceName);
    void DeviceLogout(ConnectHookPtr connPtr);
    ConnectHookPtr CreateNewHook(const oatpp::websocket::WebSocket* socketMemAddress);
    void RecyclingConnect(const oatpp::websocket::WebSocket* socketMemAddress);  //回收队列中无用的设备
    void StartCollegeImage(const long deviceID);
    void StopCollegeImage(const long deviceID);
    void EnableTriggerMode(const long deviceID);
    void DisableTriggerMode(const long deviceID);
    int32_t GetDeviceInfo(const long deviceID);
    CameraParament GetCameraPara(const long deviceID);
    void InitDevice(const long deviceID);
    void StartShot(const long deviceID);
    void StopShot(const long deviceID);
    void StartCollege(const long deviceID);
    void StopCollege(const long deviceID);
    void SetExposeTime(const long deviceID,int32_t value);
    void SetImageHeight(const long deviceID,const int32_t value);
    void SetImageWidth(const long deviceID,const int32_t value);
    void SetImageOffsetX(const long deviceID,const int32_t value);
    void SetImageOffsetY(const long deviceID,const int32_t value);
    void SetFrameRate(const long deviceID,const int32_t value);
    bool FileTransferFunc(const long deviceID,const std::string& savePath);
private:
    std::shared_mutex recyclingMut;
    static std::atomic<int> connectUUID_count; //UUID
    wxEvtHandler* _evtHandler;
    wxWindowID winID;
    std::map<uintptr_t,int> socketMap;
    std::map<int,ConnectHook> connectMap; //用于存储每一个连接
};

#endif
